package com.xiaojf.xlog.util;

import org.aspectj.lang.JoinPoint;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * aop 获取注解工具类
 *
 * @author Ade.Xiao 2021/3/11 13:38
 */
public class AopAnnotationUtil {
    /**
     * 获取注解对象
     *
     * @param joinPoint aop 切点
     * @param t
     * @return {@link T}
     * @author Ade.Xiao 2021-03-11 17:55:31
     */
    public static <T extends Annotation> T getAnnotation(JoinPoint joinPoint, Class<T> t) throws ClassNotFoundException {
        //获得执行方法的类名
        String targetName = joinPoint.getTarget().getClass().getName();
        //获得执行方法的方法名
        String methodName = joinPoint.getSignature().getName();
        //获取切点方法的所有参数类型
        Object[] arguments = joinPoint.getArgs();

        Class targetClass = Class.forName(targetName);
        //获取公共方法，不包括类私有的
        Method[] methods = targetClass.getMethods();
        String content = "";
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                //对比方法中参数的个数
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length == arguments.length) {
                    return method.getAnnotation(t);
                }
            }
        }

        return null;
    }

    /**
     * 获取切面点的上下方法参数
     *
     * @param joinPoint
     * @return {@link EvaluationContext}
     * @author Ade.Xiao 2021-03-11 17:55:55
     */
    public static <T extends Annotation> EvaluationContext getEvaluationContext(JoinPoint joinPoint) throws ClassNotFoundException {
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        String[] paramNames = {};
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                paramNames = getParamterNames(method);
            }
        }

        EvaluationContext context = new StandardEvaluationContext();
        for (int i = 0; i < arguments.length; i++) {
            context.setVariable(paramNames[i], arguments[i]);
        }

        return context;
    }

    /**
     * 解析springel 表达式, 并返回结果
     *
     * @param context 方法上下文
     * @param str     需要被解析的字符串
     * @param t       返回的结果类型
     * @return {@link T}
     */
    public static <T> T getValue(EvaluationContext context, String str, Class<T> t) {
        ExpressionParser parser = new SpelExpressionParser();
        Expression expression = parser.parseExpression(str);
        return expression.getValue(context, t);
    }

    /**
     * 返回方法的所有参数
     *
     * @param method 方法对象
     * @return {@link String[]} 参数
     * @author Ade.Xiao 2021-03-11 17:57:27
     */
    public static String[] getParamterNames(Method method) {
        LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
        return u.getParameterNames(method);
    }
}
